package load;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import tools.ImageEditor;
import tools.Tools;
import view.Page;

public class Init {
    
    public static File loading;
    public static Set<File> errorFiles = new HashSet<>();

    public static final String[] NOT_CRETIRIA = new String[] {"UC", "Ethiopia_Mode", "Ethiopia_Mode_Expansion1", "Ethiopia_Mode_Expansion2", "Ethiopia_Mode_Expansion2_GranColombia_Maya"};

    // copy databases from usr file
    public static void copyDatabases() throws IOException {
        File databaseFolder = new File(Tools.DATABASES_SOURCE);
        File destFolder = new File("database");
        if(destFolder.exists()) {
            if(destFolder.isDirectory()) {
                for(File f : destFolder.listFiles()) {
                    f.delete();
                }
            }
            destFolder.delete();
        }
        destFolder.mkdir();

        for(File file : databaseFolder.listFiles()) {
			if (file.isDirectory()) {
				continue;
			}
            File dest = new File(destFolder, file.getName());
            if(dest.exists()) {
                dest.delete();
            }
            dest.createNewFile();
            InputStream in = new FileInputStream(file);
            OutputStream out = new FileOutputStream(dest);
            byte[] buf = new byte[64];
            int len;
            while((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            out.flush();
            out.close();
            in.close();

            if (file.getName().contains("Localization")) {
                File dest_nohd = new File(destFolder, "nohd_" + file.getName());
                if(dest_nohd.exists()) {
                    dest_nohd.delete();
                }
                dest_nohd.createNewFile();
                in = new FileInputStream(file);
                OutputStream out_nohd = new FileOutputStream(dest_nohd);
                while((len = in.read(buf)) != -1) {
                    out_nohd.write(buf, 0, len);
                }
                out_nohd.flush();
                out_nohd.close();
                in.close();
            }
        }
    }

    public static void addTables() throws SQLException {
        Connection connection = DriverManager.getConnection(Tools.EXTRA_DATABASE);
        Statement statement = connection.createStatement();

        // load extra tables
        try {
            DataBaseLoader.loadSQL(new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/Base/Assets/Database/ColorManager.sql"), statement);
            DataBaseLoader.loadSQL(new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/Base/Assets/Database/IconManager.sql"), statement);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // load players colors
        try {
            DataBaseLoader.loadXMLAsData(new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/Base/Assets/UI/Colors/PlayerColors.xml"), statement);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            DataBaseLoader.loadXMLAsData(new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/Base/Assets/UI/Colors/PlayerStandardColors.xml"), statement);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        // load icon table
        File folder = new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/Base/Assets/UI/Icons");
        for(File file : folder.listFiles()) {
            try {
                DataBaseLoader.loadXMLAsData(file, statement);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        statement.close();
    }

    static class Request implements Comparable<Request> {
        String type;
        int order;
        List<File> files;
        String mod;
        @Override
        public int compareTo(Request r) {
            return order - r.order;
        }
    }

    public static void loadDLCs () throws Exception {
        List<Request> feaRequests = new ArrayList<>();
        List<Request> igaRequests = new ArrayList<>();

        // init mod file list
        File folder1 = new File(Tools.STEAM_FOLDER + "/common/Sid Meier's Civilization VI/DLC");
        File folder2 = new File(Tools.STEAM_FOLDER + "/workshop/content/289070");
        File folder3 = new File("C:/Users/xiaoxiao/Documents/My Games/Sid Meier's Civilization VI/Mods");
        List<File> dlcs = new ArrayList<>();
        for (File f : folder1.listFiles()) {
            dlcs.add(f);
        }
        for (File f : folder2.listFiles()) {
            dlcs.add(f);
        }
        for (File f : folder3.listFiles()) {
            dlcs.add(f);
        }

        // init mod requests
        for (File dlc : dlcs) {
            if(dlc.isFile()) {
                continue;
            }
            if(dlc.getName().endsWith("Scenario")) {
                continue;
            }
            File modInfo = null;
            for (File child : dlc.listFiles()) {
                if(child.getName().endsWith(".modinfo")) {
                    modInfo = child;
                    break;
                }
            }
            if (modInfo == null) {
                System.out.println("can't find .modinfo in " + dlc.getAbsolutePath());
                continue;
            }
            Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(modInfo);
            Element root = document.getDocumentElement();

            String modID = root.getAttribute("id");
            
            Element frontEndActions = (Element) root.getElementsByTagName("FrontEndActions").item(0);
            if (frontEndActions != null) {
                NodeList feaList = frontEndActions.getChildNodes();
                for (int i = 0; i < feaList.getLength(); i++) {
                    NamedNodeMap map = feaList.item(i).getAttributes();
                    if (map != null) {
                        String criteria = null;
                        try {
                            criteria = map.getNamedItem("criteria").getTextContent();
                        } catch (Exception e) {
                        }
                        if (criteria != null) {
                            boolean exist = false;
                            for (String not : NOT_CRETIRIA) {
                                if (criteria.equals(not)) {
                                    exist = true;
                                    break;
                                }
                            }
                            if (exist) {
                                continue;
                            }
                        }
                    }
                    String type = feaList.item(i).getNodeName();
                    if(!type.equals("UpdateColors") && !type.equals("UpdateIcons") && !type.equals("UpdateText") &&! type.equals("UpdateDatabase")) {
                        continue;
                    }
                    Element update = (Element) feaList.item(i);
                    Request request = new Request();
                    request.type = type;
                    request.mod = modID;
                    Element property = (Element) update.getElementsByTagName("Properties").item(0);
                    if (property == null) {
                        request.order = 0;
                    } else {
                        request.order = Integer.parseInt(property.getElementsByTagName("LoadOrder").item(0).getTextContent());
                    }
                    List<File> files = new ArrayList<>();
                    NodeList fileNodes = update.getElementsByTagName("File");
                    for (int j = 0; j < fileNodes.getLength(); j++) {
                        files.add(new File(dlc, fileNodes.item(j).getTextContent()));
                    }
                    request.files = files;
                    feaRequests.add(request);
                }
            }

            Element inGameActions = (Element) root.getElementsByTagName("InGameActions").item(0);
            if (inGameActions != null) {
                NodeList igaList = inGameActions.getChildNodes();
                for (int i = 0; i < igaList.getLength(); i++) {
                    NamedNodeMap map = igaList.item(i).getAttributes();
                    if (map != null) {
                        String criteria = null;
                        try {
                            criteria = map.getNamedItem("criteria").getTextContent();
                        } catch (Exception e) {
                        }
                        if (criteria != null) {
                            boolean exist = false;
                            for (String not : NOT_CRETIRIA) {
                                if (criteria.equals(not)) {
                                    exist = true;
                                    break;
                                }
                            }
                            if (exist) {
                                continue;
                            }
                        }
                    }
                    String type = igaList.item(i).getNodeName();
                    if(!type.equals("UpdateColors") && !type.equals("UpdateIcons") && !type.equals("UpdateText") &&! type.equals("UpdateDatabase")) {
                        continue;
                    }
                    Element update = (Element) igaList.item(i);
                    String criteria = update.getAttribute("criteria");
                    if (criteria.equals("BarbarianClans_Mode_Expansion2")
                        || criteria.equals("SecretSocieties_Mode_Expansion2")
                        || criteria.equals("Dramatic_Mode_Expansion2")
                        || criteria.equals("Apocalypse_Mode_Expansion2")
                        || criteria.equals("Heroes_Mode_Expansion2")
                        || criteria.equals("TowerDefense_Mode_Expansion2")
                        || criteria.equals("TreeRandomizer_Mode_Expansion2")
                        || criteria.equals("AITest_Mode_Expansion2")
                        || criteria.equals("Testing_Mode_Expansion2")
                        || criteria.equals("TechTest_Mode_Expansion2")
                        || criteria.equals("Wild_Mode_Expansion2")
                        || criteria.equals("MPTest_Mode_Expansion2")
						|| criteria.equals("DevTest_Mode_Expansion2")) {
                        continue;
                    }
                    Request request = new Request();
                    request.type = type;
                    request.mod = modID;
                    Element property = (Element) update.getElementsByTagName("Properties").item(0);
                    if (property == null) {
                        request.order = 0;
                    } else {
                        request.order = Integer.parseInt(property.getElementsByTagName("LoadOrder").item(0).getTextContent());
                    }
                    List<File> files = new ArrayList<>();
                    NodeList fileNodes = update.getElementsByTagName("File");
                    for (int j = 0; j < fileNodes.getLength(); j++) {
                        files.add(new File(dlc, fileNodes.item(j).getTextContent()));
                    }
                    request.files = files;
                    igaRequests.add(request);
                }
            }
        }

        System.out.println("sorting");
        Collections.sort(feaRequests);
        Collections.sort(igaRequests);

        Statement gameplayStatement = DriverManager.getConnection(Tools.GAMEPLAY_DATABASE).createStatement();
        Statement extraStatement = DriverManager.getConnection(Tools.EXTRA_DATABASE).createStatement();
        Statement textStatement = DriverManager.getConnection(Tools.TEXT_DATABASE).createStatement();
        Statement nohdTextStatement = DriverManager.getConnection(Tools.NOHD_TEXT_DATABASE).createStatement();
        int n = 0;
        int N = feaRequests.size() + igaRequests.size();
        for (Request request : feaRequests) {
            System.out.println(n + "/" + N + ": order=" + request.order + " " + "files=" + request.files.size());
            n++;
            for (File file : request.files) {
                loading = file;
                try {
                    switch (request.type) {
                        case "UpdateColors":
                        case "UpdateIcons": {
                            //DataBaseLoader.loadAsData(file, extraStatement);
                            break;
                        }
                        case "UpdateText": {
                            //DataBaseLoader.loadAsData(file, textStatement);
                            break;
                        }
                        case "UpdateDatabase": {
                            //DataBaseLoader.loadAsData(file, gameplayStatement);
                            break;
                        }
                    }
                } catch (Exception e) {
                    System.out.println(e.getClass().getName() + " " + e.getMessage() + " " + file.getAbsolutePath());
                }
            }
        }
        for (Request request : igaRequests) {
            System.out.println(n + "/" + N + ": order=" + request.order + " " + "files=" + request.files.size());
            n++;
            for (File file : request.files) {
                loading = file;
                try {
                    switch (request.type) {
                        case "UpdateColors":
                        case "UpdateIcons": {
                            DataBaseLoader.loadAsData(file, extraStatement);
                            break;
                        }
                        case "UpdateText": {
                            DataBaseLoader.loadAsData(file, textStatement);
                            if (!(request.mod.equals("521b8777-0977-4859-a5ee-3e411a732e5c") // hd main
                            || request.mod.equals("66add898-b3bb-4bd9-98a2-805d37f0da2e") // hd district
                            || request.mod.equals("c0417322-9747-42d5-9717-b0df5a4c6e5d") // hd city-states
                            || request.mod.equals("c086b5a6-90d2-4dea-a32f-c642639b9469") // hd I&C
                            )) {
                                //DataBaseLoader.loadAsData(file, nohdTextStatement);
                            }
                            break;
                        }
                        case "UpdateDatabase": {
                            //DataBaseLoader.loadAsData(file, gameplayStatement);
                            break;
                        }
                    }
                } catch (Exception e) {
                    System.out.println(e.getClass().getName() + " " + e.getMessage() + " " + file.getAbsolutePath());
                }
            }
        }
        gameplayStatement.close();
        extraStatement.close();
        textStatement.close();
        nohdTextStatement.close();
    }

    public static void initFix() {
        try {
            Statement extra = DriverManager.getConnection(Tools.EXTRA_DATABASE).createStatement();
            DataBaseLoader.loadSQL(new File("fix_extra.sql"), extra);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void writeErrors() throws Exception {
        File error = new File("icons/errors.txt");
        if(error.exists()) {
            error.delete();
        }
        error.createNewFile();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(error)));
        for (File f : errorFiles) {
            writer.write(f.getAbsolutePath() + "\n");
        }
        writer.flush();
        writer.close();
    }

    // manual fix before running this :
    
    // replace <?xml version="2.0" encoding="utf-8"?>
    // with <?xml version="1.0" encoding="utf-8"?> in
    // C:\Program Files (x86)\Steam\steamapps\common\Sid Meier's Civilization VI\DLC\Ethiopia\Data\Ethiopia_Icons_Buildings.xml

    // delete comments at the beginning of
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\1579019534\Icons\FontIconsRMI.xml
    // and
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\1312585482\Icons\FontIconsRMI.xml

    // add </Replace> at near end of
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\1770688835\Text\Globe_Theatre_Text.xml

    // fix & with &amp; in
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\1770703400\Text\Burj_Khalifa_Text.xml

    // replace insert into with insert or ignore into in
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\2542898147\Core\Suk_Oceans_Icons.sql

    // delete TEMPORARY in
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\2542898147\Core\Monopolies\Suk_AltEcon_Common.sql
    // and
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\2155632734\Core_MODE\LatResources_Monopolies_Text.sql
    // and
    // C:\Program Files (x86)\Steam\steamapps\workshop\content\289070\2616754773\HD_Monopoly_Text.sql
    public static void init() {
        try {
            copyDatabases();
            addTables();
            loadDLCs();
            initFix();
            writeErrors();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void initIcons () throws Exception {
        Statement extra = DriverManager.getConnection(Tools.EXTRA_DATABASE).createStatement();
        File iconFile = new File ("icons/icons.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(iconFile)));
        List<String> icons = new ArrayList<>();
        String line;
        while ((line = reader.readLine()) != null) {
            icons.add(line);
        }
        reader.close();
        for (String civilopedia : Page.HEADERS) {
            icons.add("icon_civilopedia_" + civilopedia);
        }
        for (String icon : icons) {
            BufferedImage image = null;
            File file = new File("icons/" + icon + ".png");
            ResultSet r1 = extra.executeQuery("select * from IconDefinitions where lower(Name) = \"" + icon + "\";");
            if (r1.next()) {
                icon = r1.getString("Name");
                image = Tools.getImage(icon);
            }
            if (image == null && file.exists()) {
                System.out.println("manually replaced " + icon);
                image = ImageIO.read(file);
            }
            if (image == null) {
                System.out.println("can't find " + icon);
            }
            String path;
            path = (icon.toUpperCase().startsWith("ICON_") ? "" : "ICON_") + icon.toUpperCase() + ".png";
            ImageEditor.saveImage(image, path);
        }
    }

    public static void main(String[] args) throws Exception {
        init();
        initIcons();
    }

}
